using NUnit.Framework;
using Tycho.Parser.Peg;

namespace Tycho.Parser.Tests.Peg {
    [TestFixture]
    public class MultipleRuleSpecification {
        [Test]
        public void ZeroOrMoreParseShouldSucceedWhenNothingParsed () {
            var m = new MultipleRule (0, -1, new KeywordRule ("x"));

            var source = "";

            var result = m.Parse (source, 0, new ParseContext ());

            Assert.IsNotNull (result);
            Assert.AreEqual (0, result.Index);
        }

        [Test]
        public void OneOrMoreParseShouldSucceedWhenJustOneParsed () {
            var m = new MultipleRule (1, -1, new KeywordRule ("x"));

            var source = "x";

            var result = m.Parse (source, 0, new ParseContext ());

            Assert.IsNotNull (result);
            Assert.AreEqual (1, result.Index);
        }

        [Test]
        public void ThreeOrMoreParseShouldFailWhenJustTwoParsed () {
            var m = new MultipleRule (3, -1, new KeywordRule ("x"));

            var source = "x x";

            var result = m.Parse (source, 0, new ParseContext ());

            Assert.IsNull (result);
        }

        [Test]
        public void OneToTwoParseShouldSucceedWhenThreeFoundToParse () {
            var m = new MultipleRule (1, 2, new KeywordRule ("x"));

            var source = "x x x";

            var result = m.Parse (source, 0, new ParseContext ());

            Assert.IsNotNull (result);
            Assert.AreEqual (3, result.Index);
        }

        [Test]
        public void OneToTwoParseShouldFailWhenNoneFoundToParse () {
            var m = new MultipleRule (1, 2, new KeywordRule ("x"));

            var source = "y";

            var result = m.Parse (source, 0, new ParseContext ());

            Assert.IsNull (result);
        }

        [Test]
        public void ZeroOrMoreParseShouldSucceedWhenNoneFoundToParse () {
            var m = new MultipleRule (0, -1, new KeywordRule ("x"));

            var source = "y";

            var result = m.Parse (source, 0, new ParseContext ());

            Assert.IsNotNull (result);
            Assert.AreEqual (0, result.Index);
        }

        [Test]
        public void ParseShouldReturnAllCapturesWhenSuccessful () {
            var m = new MultipleRule (0, -1, new NamedRule ("id", IdentifierProduction.CreateTerminal ()));

            var source = "a b c";

            var result = m.Parse (source, 0, new ParseContext ());

            Assert.IsNotNull (result);
            Assert.AreEqual (3, result.Captures.Count);
            result.AssertCaptureIs (0, "id", "a");
            result.AssertCaptureIs (1, "id", "b");
            result.AssertCaptureIs (2, "id", "c");
        }
    }

    static class CaptureHelper {
        public static void AssertCaptureIs (this RuleParseResult result, int index, string name, string identifier) {
            Assert.AreEqual (name, result.Captures [index].Name);
            Assert.AreEqual (identifier, ((IdentifierTerm) result.Captures [index].Term).Name);
        }
    }
}